package com.computergames.server.server.client;

import com.computergames.server.message.*;
import com.computergames.server.message.cardMessage.BidRequestMessage;
import com.computergames.server.message.cardMessage.BidResponseMessage;
import com.computergames.server.message.cardMessage.DealMessage;
import com.computergames.server.message.cardMessage.LandlordMessage;
import com.computergames.server.message.chessMessage.GobangMessage;
import com.computergames.server.protocol.MessageCodecSharable;
import com.computergames.server.protocol.ProtocolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.mindrot.jbcrypt.BCrypt;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
public class Client2 {
    private static String jwtToken = null;
    private static String roomName = null;
    private static boolean isStageChoiceSuccess = false;
    public static void main(String[] args)
    {
        NioEventLoopGroup group = new NioEventLoopGroup();
        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.INFO);
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
        CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1);
        CountDownLatch WAIT_FOR_CHOICE_MODE = new CountDownLatch(1);
        CountDownLatch WAIT_FOR_CHOICE_STAGE = new CountDownLatch(1);
        AtomicBoolean LOGIN = new AtomicBoolean(false);
        AtomicBoolean EXIT = new AtomicBoolean(false);
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ProtocolFrameDecoder());
                            ch.pipeline().addLast(LOGGING_HANDLER);
                            ch.pipeline().addLast(MESSAGE_CODEC);
                            ch.pipeline().addLast(new IdleStateHandler(0, 0, 0));
                            ch.pipeline().addLast(new ChannelDuplexHandler() {
                                @Override
                                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                    IdleStateEvent event = (IdleStateEvent) evt;
                                    if(event.state() == IdleState.WRITER_IDLE){
                                        //log.info("20秒没有写数据，自动发送一个心跳包");
                                        ctx.writeAndFlush(new PingMessage());
                                    }
                                }
                            });
                            ch.pipeline().addLast("client handler", new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    log.info("msg:{}", msg);
                                    if (msg instanceof LoginPromptMessage) {
                                        LoginPromptMessage loginPromptMessage = (LoginPromptMessage) msg;
                                        System.out.println(loginPromptMessage.getData());
                                    }
                                    else if (msg instanceof LoginResponseMessage) {
                                        LoginResponseMessage responseMessage = (LoginResponseMessage) msg;
                                        if (responseMessage.isSuccess()) {
                                            jwtToken = responseMessage.getData();
                                            System.out.println(responseMessage.getModeChoiceResponse());
                                            //如果登录成功
                                            LOGIN.set(true);
                                        }
                                        //唤醒system in 线程
                                        WAIT_FOR_LOGIN.countDown();
                                    }
                                    else if (msg instanceof ModeSelectionResponseMessage) {
                                        ModeSelectionResponseMessage responseMessage = (ModeSelectionResponseMessage) msg;
                                        if (responseMessage.isSuccess()) {
                                            System.out.println(responseMessage.getData());
                                        }
                                        //唤醒system in 线程
                                        WAIT_FOR_CHOICE_MODE.countDown();
                                    }
                                    else if (msg instanceof StageSelectionResponseMessage) {
                                        StageSelectionResponseMessage responseMessage = (StageSelectionResponseMessage) msg;
                                        if (responseMessage.isSuccess()) {
                                            System.out.println(responseMessage.getData());
                                            isStageChoiceSuccess = true;
                                        }
                                        //唤醒system in 线程
                                        WAIT_FOR_CHOICE_STAGE.countDown();
                                    }
                                    else if (msg instanceof CreateRoomResponseMessage){
                                        CreateRoomResponseMessage responseMessage = (CreateRoomResponseMessage) msg;
                                        String data = responseMessage.getData();
                                        System.out.println(data);
                                        String[] parts = data.split("房间人数已满，请准备", 2);
                                        roomName = parts[0];
                                    }
                                    else if (msg instanceof JoinRoomResponseMessage){
                                        JoinRoomResponseMessage responseMessage = (JoinRoomResponseMessage) msg;
                                        String data = responseMessage.getData();
                                        String[] parts = data.split("房间人数已满，请准备", 2);
                                        roomName = parts[0];
                                    }
                                    else if (msg instanceof DealMessage){
                                        DealMessage dealMessage = (DealMessage) msg;
                                        System.out.println(dealMessage.getData());
                                    }
                                    else if (msg instanceof BidResponseMessage){
                                        BidResponseMessage responseMessage = (BidResponseMessage) msg;
                                        if (responseMessage.isSuccess()) {
                                            System.out.println(responseMessage.getData());
                                        }
                                    }
                                    else if (msg instanceof MoveResponseMessage){
                                        MoveResponseMessage responseMessage = (MoveResponseMessage) msg;
                                        System.out.println(responseMessage.getData());
                                    }
                                }

                                //在连接建立后，发送一个消息给服务器
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    new Thread(()->{
                                        Scanner scanner = new Scanner(System.in);
                                        //System.out.println("请输入用户名：");
                                        String username = scanner.nextLine();
                                        if(EXIT.get()){
                                            return;
                                        }
                                        //System.out.println("请输入密码：");
                                        String password = scanner.nextLine();
                                        if(EXIT.get()){
                                            return;
                                        }
                                        // 对密码进行散列处理
                                        String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt(12));
                                        ctx.writeAndFlush(new LoginRequestMessage(username, hashedPassword));

                                        System.out.println("等待后续操作...");
                                        try {
                                            WAIT_FOR_LOGIN.await();
                                        } catch (InterruptedException e) {
                                            throw new RuntimeException(e);
                                        }
                                        //如果登录失败
                                        if (!LOGIN.get()) {
                                            ctx.close();
                                            return;
                                        }

                                        int modeChoice = Integer.parseInt(scanner.nextLine());
                                        ctx.writeAndFlush(new ModeSelectionRequestMessage(modeChoice, jwtToken));
                                        System.out.println("等待后续操作...");
                                        try {
                                            WAIT_FOR_CHOICE_MODE.await();
                                        } catch (InterruptedException e) {
                                            throw new RuntimeException(e);
                                        }

                                        int stageChoice = Integer.parseInt(scanner.nextLine());
                                        ctx.writeAndFlush(new StageSelectionRequestMessage(stageChoice, jwtToken));
                                        try {
                                            WAIT_FOR_CHOICE_STAGE.await();
                                        } catch (InterruptedException e) {
                                            throw new RuntimeException(e);
                                        }

                                        while(isStageChoiceSuccess){
                                            String command = null;
                                            try {
                                                command = scanner.nextLine();
                                            } catch (Exception e) {
                                                break;
                                            }
                                            if(EXIT.get()){
                                                return;
                                            }
                                            String[] s = command.split(" ");
                                            switch (s[0]){
                                                case "create":
                                                    // 使用LinkedHashSet来保证唯一性并维持插入顺序，之后再转为ArrayList
                                                    LinkedHashSet<String> uniqueMembers = new LinkedHashSet<>();
                                                    uniqueMembers.add(username); // 确保username第一个添加

                                                    // 检查命令是否有足够的参数，s[3]是否存在
                                                    if (s.length > 3) {
                                                        // 处理额外的成员
                                                        String[] elements = s[3].split(",");
                                                        for (String element : elements) {
                                                            // 如果元素不是username，才添加到集合中，确保username始终保持第一个且集合中没有重复
                                                            if (!element.equals(username)) {
                                                                uniqueMembers.add(element);
                                                            }
                                                        }
                                                    }
                                                    // 将LinkedHashSet转换为ArrayList以保持顺序
                                                    List<String> memberList = new ArrayList<>(uniqueMembers);
                                                    ctx.writeAndFlush(new CreateRoomRequestMessage(s[1], s[2], memberList, jwtToken));
                                                    break;
                                                case "join":
                                                    ctx.writeAndFlush(new JoinRoomRequestMessage(s[1],username, jwtToken));
                                                    break;
                                                case "ready":
                                                    String isReady = s[1];
                                                    ctx.writeAndFlush(new ReadyRequestMessage(Boolean.parseBoolean(isReady), jwtToken));
                                                    break;
                                                case "acknowledge":
                                                    ctx.writeAndFlush(new AcknowledgeMessage(s[1]+" "+s[2], jwtToken));
                                                    break;
                                                case "members":
                                                    ctx.writeAndFlush(new RoomMembersRequestMessage(s[1], jwtToken));
                                                    break;
                                                case "send":
                                                    String[] coordinate;
                                                    if(s[2].contains(",")){
                                                        coordinate = s[2].split(",");
                                                    } else {
                                                        coordinate = new String[]{s[2]};
                                                    }
                                                    try {
                                                        ctx.writeAndFlush(new MoveRequestMessage(username, new GobangMessage(s[1], coordinate), jwtToken));
                                                    } catch (NumberFormatException e) {
                                                        System.out.println("The string cannot be parsed to an integer.");
                                                    }
//                                                    String[] card;
//                                                    if(s[1].contains(",")){
//                                                        card = s[1].split(",");
//                                                    } else {
//                                                        card = new String[]{s[1]};
//                                                    }
//                                                    try {
//                                                        ctx.writeAndFlush(new MoveRequestMessage(username, new LandlordMessage(card), jwtToken));
//                                                    } catch (NumberFormatException e) {
//                                                        System.out.println("The string cannot be parsed to an integer.");
//                                                    }
                                                    break;
                                                case "bid":
                                                    try {
                                                        ctx.writeAndFlush(new BidRequestMessage(s[1], Integer.parseInt(s[2]), jwtToken));
                                                    } catch (NumberFormatException e) {
                                                        System.out.println("The string cannot be parsed to an integer.");
                                                    }
                                                    break;
                                                case "quit":
                                                    ctx.writeAndFlush(new QuitRoomRequestMessage(username, jwtToken));
                                                    break;
                                                case "shutdown":
                                                    ctx.channel().close();
                                                    return;
                                                default:
                                                    System.out.println("输入有误，请重新输入");
                                            }
                                        }
                                    }, "system in").start();
                                }
                                // 在连接断开时触发
                                @Override
                                public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                    log.info("连接已经断开，按任意键退出..");
                                    EXIT.set(true);
                                }

                                // 在出现异常时触发
                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    log.info("连接已经断开，按任意键退出..{}", cause.getMessage());
                                    EXIT.set(true);
                                }
                            });
                        }
                    });
            Channel channel = bootstrap.connect("localhost", 8081).sync().channel();
            channel.closeFuture().sync();
        }catch (InterruptedException e){
            log.error("server error", e);
        } finally {
            group.shutdownGracefully();
        }
    }
}
